package com.lw.common.file;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.lw.common.utils.CommonUtils;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 本地存储服务类
 *
 * @author Theo
 * @since 2024-12-09 17:11
 */
@Data
@Slf4j
@Component
@ConditionalOnProperty(value = "oss.type", havingValue = "local")
@ConfigurationProperties(prefix = "oss.local")
@RequiredArgsConstructor
public class LocalFileService implements FileService {

    private static final ConcurrentHashMap<String, Integer> chunkCountMap = new ConcurrentHashMap<>();

    private static final String BUCKET_NAME = "your-bucket-name"; // 替换为你的桶名称

    @Resource
    ApplicationContext applicationContext;

    @Resource
    CommonUtils commonUtils;

    @Value("${oss.local.storage-path}")
    private String storagePath;

    /**
     * 上传文件方法
     *
     * @param file 表单文件对象
     * @return 文件信息
     */
    @Override
    public FileInfo uploadFile(MultipartFile file) {
        // 获取文件名
        String originalFilename = file.getOriginalFilename();
        // 获取文件后缀
        String suffix = FileUtil.getSuffix(originalFilename);
        // 生成uuid
        String fileName = IdUtil.simpleUUID() + "." + suffix;
        // 生成文件名(日期文件夹)
        String folder = DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
        //  try-with-resource 语法糖自动释放流
        try (InputStream inputStream = file.getInputStream()) {
            // 上传文件
            FileUtil.writeFromStream(inputStream, commonUtils.getUploadFullFilePathByTime(fileName, folder));
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败");
        }
        // 获取文件访问路径，因为这里是本地存储，所以直接返回文件的相对路径，需要前端自行处理访问前缀
        String fileUrl = File.separator + folder + File.separator + fileName;
        FileInfo fileInfo = new FileInfo();
        String applicationName = applicationContext.getApplicationName();
        fileInfo.setName(originalFilename);
        fileInfo.setUrl(applicationName + File.separator + "static" + fileUrl);
        return fileInfo;
    }


    /**
     * 删除文件
     *
     * @param filePath 文件完整URL
     * @return 是否删除成功
     */
    @Override
    public boolean deleteFile(String filePath) {
        //判断文件是否为空
        if (filePath == null || filePath.isEmpty()) {
            return false;
        }
        // 判断filepath是否为文件夹
        if (FileUtil.isDirectory(storagePath + filePath)) {
            // 禁止删除文件夹
            return false;
        }
        // 删除文件
        return FileUtil.del(storagePath + filePath);
    }

    @Override
    public String uploadByChunk(MultipartFile file, int chunkNumber, int totalChunks) {
        String fileNameOrigin = file.getOriginalFilename();
        String fileName = fileNameOrigin + "_part_" + chunkNumber;
        //全路径
        String fullFilePath = commonUtils.getUploadFilePath(fileName);
        ;
        System.out.println("全路径:" + fullFilePath);
        try (InputStream inputStream = file.getInputStream()) {
            // 上传文件
            FileUtil.writeFromStream(inputStream, fullFilePath);
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败");
        }
        return "Uploaded chunk " + chunkNumber + " of " + totalChunks;
    }

    @Override
    public HashMap<String, Boolean> checkChunkUploaded(String fileName, int chunkNumber) {
        // 检查文件是否存在
        String fullFilePath = commonUtils.getUploadFilePath(fileName);
        HashMap<String, Boolean> result = new HashMap<>();
        result.put("uploaded", FileUtil.exist(fullFilePath));
        return result;
    }

    @SneakyThrows
    @Override
    public String mergeChunks(String fileName, int totalChunks) {
        // 创建临时文件用于合并
        Path tempFilePath = Paths.get(fileName);
        OutputStream outputStream = new FileOutputStream(tempFilePath.toFile());

        for (int i = 1; i <= totalChunks; i++) {
            String tempFileName = fileName + "_part_" + i;
            // 读取分片文件并写入临时文件
            InputStream inputStream = new FileInputStream(commonUtils.getUploadFilePath(tempFileName));

            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            inputStream.close();

            // 删除临时分片文件
            FileUtil.del(commonUtils.getUploadFilePath(tempFileName));
        }
        outputStream.close();

        //将临时文件保存
        FileUtil.move(tempFilePath.toFile(), new File(storagePath), true);


        // 清除缓存中的分片计数
        chunkCountMap.remove(fileName);
        return "Merged all chunks successfully.";

    }
}
